#include <iostream>
#include <string>
#include <sys/select.h>
#include <cmath>
#include <poll.h>

#include "log.hpp"
#include "Socket.hpp"

using namespace Net_work;

const static int gbacklog = 8; // Tcp 在底层所能维护的全链接队列
const static int num = sizeof(fd_set) * 8;

class PollServer
{

    int _port;
    std::unique_ptr<Socket> _listensock;
    int _isrunning;

    struct pollfd *_rfds;
    int _num;

public:
    PollServer(int port) : _port(port), _listensock(new TcpSocket()), _isrunning(false), _num(num)
    {
    }

    ~PollServer()
    {
        delete[] _rfds;
    }

    void InitServer()
    {
        _listensock->BuildListenSocket(_port, gbacklog);
        _rfds = new struct pollfd[_num];

        for (int i = 0; i < _num; i++)
        {
            _rfds[i].fd = -1;
            _rfds[i].events = 0;
            _rfds[i].revents = 0;
        }

        // 最开始存在 linsten sockfd
        _rfds[0].fd = _listensock->GetSockFd();
        _rfds[0].events |= POLLIN; //! 新连接到来是 POLLIN
    }

    void HandlerEvent()
    {
        for (int i = 0; i < _num; i++)
        {
            if (_rfds[i].fd == -1)
                continue;

            int fd = _rfds[i].fd;
            short revent = _rfds[i].revents;

            if (revent & POLLIN) // POLLIN  listensock -> 新链接到来
            {
                if (fd == _listensock->GetSockFd()) // rfds 中是否存在 Listen 套接字
                {
                    // 说明 _listensock 中产生新的连接
                    std::string clientip;
                    uint16_t clientport;
                    Socket *sock = _listensock->AcceptConnection(&clientip, &clientport);
                    if (!sock)
                    {
                        lg.LogMessage(Error, "accept error!\n");
                        return;
                    }
                    lg.LogMessage(Info, "get a new link, ip:port -> %s:%d , sockfd: %d \n", clientip.c_str(), clientport, sock->GetSockFd());
                    // 将新的 fd(文件描述符) 添加进入sockfd_array

                    int pos = 0;
                    for (; pos < _num; pos++)
                    {
                        if (_rfds[pos].fd == -1) // 当前未知没有被使用
                        {
                            lg.LogMessage(Info, "get a new link!\n");
                            _rfds[pos].fd = sock->GetSockFd();
                            _rfds[pos].events = POLLIN; // 关心读时间
                            break;
                        }
                    }

                    if (pos == _num)
                    {
                        // pos == num
                        // 说明服务器已经满载了
                        sock->CloseSocket();
                        delete sock;
                        lg.LogMessage(Warning, "server is full ...! \n");
                    }
                }
                else
                {
                    // 普通文件描述符 事件就绪

                    // ?  这里数据读取是有问题的
                    char inbuffer[1024];
                    ssize_t n = recv(_rfds[i].fd, inbuffer, sizeof inbuffer - 1, 0);
                    if (n > 0)
                    {
                        inbuffer[n] = 0;
                        std::string message = "client say# ";
                        message += inbuffer;
                        send(_rfds[i].fd, message.c_str(), message.size(), 0);
                    }
                    else
                    {
                        lg.LogMessage(Warning, "client quit\n");
                        close(_rfds[i].fd);

                        // 关闭还需要取消 poll 的关系

                        _rfds[i].events = 0;
                        _rfds[i].fd = -1;
                        _rfds[i].revents = 0;
                    }
                }
            }
        }
    }

    void Loop()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // 定义时间
            int timeout = 1000;

            PrintDeBug();

            int n = poll(_rfds, _num, timeout);

            // 0 代表超时
            // -1 代表出错
            // 否则就是正常的

            switch (n)
            {
            case 0:
                lg.LogMessage(Info, "poll timeout\n");
                break;
            case -1:
                lg.LogMessage(Error, "poll error!\n");
                break;

            default:
                // 就绪了,正常的fd
                lg.LogMessage(Info, "select success\n");
                HandlerEvent();
                break;
            }
        }
        _isrunning = false;
    }

    void PrintDeBug()
    {
        
        std::cout << "sockfd list: ";
        for (int i = 0; i < num; i++)
        {
            if (_rfds[i].fd == -1)
            {
                continue;
            }
            else
            {
                std::cout << _rfds[i].fd << " ";
            }
        }
        std::cout << std::endl;
    }
};
